Skip to content

feat: max_eval_orig_size to restrain eval images loaded to a maximum size on the longest side - #1033

Draft
thepian wants to merge 2 commits into
roboflow:developfrom
thepian:feature/max-eval-img-size
Draft

feat: max_eval_orig_size to restrain eval images loaded to a maximum size on the longest side#1033
thepian wants to merge 2 commits into
roboflow:developfrom
thepian:feature/max-eval-img-size

Conversation

@thepian

@thepian thepian commented May 8, 2026

Copy link
Copy Markdown

This helps speed up validation epochs

What does this PR do?

Allows you to do eval with images sized to represent the scaled down images rf-detr works on.

Related Issue(s): 416

Type of Change

  • New feature (non-breaking change that adds functionality)

Testing

  • I have tested this change locally
  • I have added/updated tests for this change

Test details:
I haven't tested it a bunch. I am giving it a run with my fine tuning runs. Hopefully I get the expected speedup.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code where necessary, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have updated the documentation accordingly (if applicable)

…size on the longest side

This helps speed up validation epochs
@CLAassistant

CLAassistant commented May 8, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Borda Borda changed the title feat: max_eval_orig_size to restrain eval images loaded to a maximum … feat: max_eval_orig_size to restrain eval images loaded to a maximum size on the longest side May 13, 2026
@Borda Borda added the enhancement New feature or request label May 13, 2026
@Borda

Borda commented May 13, 2026

Copy link
Copy Markdown
Member

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

@thepian could you pls sign or share a printscreen documenting that you did, and it is just not projected in CI

@Borda
Borda marked this pull request as draft May 13, 2026 21:41
@codecov

codecov Bot commented May 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.64516% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 80%. Comparing base (b95246f) to head (e5a8d11).
⚠️ Report is 32 commits behind head on develop.

❌ Your patch check has failed because the patch coverage (81%) is below the target coverage (95%). You can increase the patch coverage or adjust the target coverage.
❌ Your project check has failed because the head coverage (80%) is below the target coverage (95%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@           Coverage Diff           @@
##           develop   #1033   +/-   ##
=======================================
- Coverage       80%     80%   -0%     
=======================================
  Files          101     101           
  Lines         8524    8553   +29     
=======================================
+ Hits          6848    6871   +23     
- Misses        1676    1682    +6     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@isaacrob

Copy link
Copy Markdown
Contributor

help me understand: the goal here is to reduce memory / RLE conversion runtime for seg models by capping the max size that the mask is stored at? probably the right test is to see what mAP the COCO models get when using different caps to show that your guess that it doesn't hurt much is right

@Borda

Borda commented Jul 21, 2026

Copy link
Copy Markdown
Member

help me understand: the goal here is to reduce memory / RLE conversion runtime for seg models by capping the max size that the mask is stored at? probably the right test is to see what mAP the COCO models get when using different caps to show that your guess that it doesn't hurt much is right

@thepian ^^ 🦝

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new max_eval_orig_size knob to cap evaluation-time “original size” used during postprocessing/COCO evaluation, aiming to reduce mask upsampling/memory and speed up validation epochs (without changing training-time behavior).

Changes:

  • Introduces TrainConfig.max_eval_orig_size (optional) and wires it into COCOEvalCallback.
  • Caps orig_sizes passed into PostProcess during val/test steps, and adds COCO-eval-side conversions to keep preds/targets consistent under the cap.
  • Adds unit tests covering mask/box scaling behavior and config defaults/inheritance.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/training/test_coco_eval_callback.py Adds tests asserting masks/boxes/targets are resized/scaled consistently when capped.
tests/models/test_config.py Adds config tests for the new field’s default and inheritance.
src/rfdetr/training/trainer.py Plumbs max_eval_orig_size from TrainConfig into COCOEvalCallback.
src/rfdetr/training/module_model.py Caps orig_sizes before calling PostProcess in val/test to reduce upsampling cost.
src/rfdetr/training/callbacks/coco_eval.py Applies the cap for EMA eval path and normalizes preds/targets under the capped size.
src/rfdetr/config.py Adds max_eval_orig_size to TrainConfig.

Comment thread src/rfdetr/config.py
Comment on lines 503 to 507
eval_max_dets: int = 500
eval_interval: int = 1
log_per_class_metrics: bool = True
max_eval_orig_size: Optional[int] = None
aug_config: Optional[Dict[str, Any]] = None
Comment on lines +223 to +226
cap = getattr(self.train_config, "max_eval_orig_size", None)
if cap is not None:
scale = (cap / orig_sizes.float().amax(dim=1, keepdim=True)).clamp(max=1.0)
orig_sizes = (orig_sizes.float() * scale).long()
Comment on lines +362 to +365
cap = getattr(self.train_config, "max_eval_orig_size", None)
if cap is not None:
scale = (cap / orig_sizes.float().amax(dim=1, keepdim=True)).clamp(max=1.0)
orig_sizes = (orig_sizes.float() * scale).long()
Comment on lines +194 to +199
if self._max_eval_orig_size is not None:
# Cap each (H, W) so the longer side ≤ max_eval_orig_size.
# Masks are upsampled to orig_size inside postprocess; capping here
# keeps mask buffers small without affecting training.
scale = (self._max_eval_orig_size / orig_sizes.float().amax(dim=1, keepdim=True)).clamp(max=1.0)
orig_sizes = (orig_sizes.float() * scale).long()
Comment on lines +732 to +742
scale = self._max_eval_orig_size / max(h, w)
new_h = max(1, int(h * scale))
new_w = max(1, int(w * scale))
masks = F.interpolate(
masks.float().unsqueeze(1),
size=(new_h, new_w),
mode="nearest",
).squeeze(1)
if "boxes" in entry:
entry["boxes"] = entry["boxes"] * scale
entry["masks"] = masks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request has conflicts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants